/*
 * QueueImpl.h
 *
 *  Created on: 2011/06/21
 *      Author: naoki
 */

#ifndef INCLUDED_NTENGINE_QUEUEIMPL_H
#define INCLUDED_NTENGINE_QUEUEIMPL_H

#include "NTEngine/NTEngine.h"
#include "NTEngine/Base/Queue.h"

namespace NTEngine {

template< class T > inline Queue< T >::Queue()
: mElements( 0 )
, mSize( 0 )
, mCapacity( 0 )
, mFront( 0 )
{
}

template< class T > inline Queue< T >::Queue( int capacity )
: mElements( 0 )
, mSize( 0 )
, mCapacity( 0 )
, mFront( 0 )
{
	if ( capacity <= 0 ) {
		return;
	}
	mCapacity = capacity;
	mElements = static_cast< T* >( OPERATOR_NEW( sizeof(T) * mCapacity ) );
}

template< class T > inline Queue< T >::~Queue() {
	if ( mElements ) {
		clear();
		OPERATOR_DELETE( mElements );
	}
}

template< class T > inline void Queue< T >::setCapacity( int capacity ) {
	ASSERT( ( mSize == 0 ) && "not empty." );
	if ( mElements ) {
		clear();
		OPERATOR_DELETE( mElements );
	}
	mCapacity = mFront = 0;
	if ( capacity <= 0 ) {
		return;
	}
	mCapacity = capacity;
	mElements = static_cast< T* >( OPERATOR_NEW( sizeof(T) * mCapacity ) );
}

template< class T > inline int Queue< T >::capacity() const {
	return mCapacity;
}

template< class T > inline int Queue< T >::size() const {
	return mSize;
}

template< class T > inline void Queue< T >::clear() {
	int back = mFront + mSize - 1;
	if ( back < mCapacity ) {
		for ( int i = mFront; i < back; ++i ) {
			mElements[ i ].~T();
		}
	}
	else {
		// 先頭要素から配列の末尾まで行って
		for ( int i = mFront; i < mCapacity; ++i ) {
			mElements[ i ].~T();
		}
		// 配列の先頭から末尾の要素まで
		back -= mCapacity;
		for ( int i = 0; i <= back; ++i ) {
			mElements[i].~T();
		}
	}
	mFront = mSize = 0;
}

template< class T > inline T* Queue< T >::pushBack() {
	ASSERT( ( mSize < mCapacity ) && "cannot push." );
	int back = mFront + mSize;
	if ( back >= mCapacity ) {
		back -= mCapacity;
	}
	new ( &mElements[ back ] ) T;
	++mSize;
	return &mElements[ back ];
}

template< class T > inline void Queue< T >::pushBack( const T& v ) {
	ASSERT( ( mSize < mCapacity ) && "cannot push." );
	int back = mFront + mSize;
	if ( back >= mCapacity ) {
		back -= mCapacity;
	}
	new ( &mElements[ back ] ) T( v );
	++mSize;
}

template< class T > inline void Queue< T >::popFront() {
	ASSERT( mSize > 0 );
	mElements[ mFront ].~T();
	++mFront;
	if ( mFront == mCapacity ) {
		mFront = 0;
	}
	--mSize;
}

template< class T > inline void Queue< T >::popFront( T* out ) {
	ASSERT( mSize > 0 );
	*out = mElements[ mFront ];
	mElements[ mFront ].~T();
	++mFront;
	if ( mFront == mCapacity ) {
		mFront = 0;
	}
	--mSize;
}

template< class T > inline const T* Queue< T >::front() const {
	ASSERT( mSize > 0 );
	return &mElements[ mFront ];
}

template< class T > inline T* Queue< T >::front() {
	ASSERT( mSize > 0 );
	return &mElements[ mFront ];
}

} // namespace NTEngine

#endif // INCLUDED_NTENGINE_QUEUEIMPL_H
